home *** CD-ROM | disk | FTP | other *** search
- /*
- * Copyright (C) 1994, Silicon Graphics, Inc.
- * All Rights Reserved.
- *
- * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics, Inc.;
- * the contents of this file may not be disclosed to third parties, copied or
- * duplicated in any form, in whole or in part, without the prior written
- * permission of Silicon Graphics, Inc.
- *
- * RESTRICTED RIGHTS LEGEND:
- * Use, duplication or disclosure by the Government is subject to restrictions
- * as set forth in subdivision (c)(1)(ii) of the Rights in Technical Data
- * and Computer Software clause at DFARS 252.227-7013, and/or in similar or
- * successor clauses in the FAR, DOD or NASA FAR Supplement. Unpublished -
- * rights reserved under the Copyright Laws of the United States.
- */
-
-
- /***********************************************************************
- *
- * Simulated reverberation for real-time audio input and output.
- *
- * The algorithms generate room ambience rather than a realistic room
- * response. For proper operation, ensure the input and output sampling
- * rates are equal and neither changes over time.
- *
- * The most advanced algorithm in this code is moorer2er19, which
- * consumes roughly 50% of a 100 MHz R4000.
- *
- * For the pronounced effect, try:
- * > reverb -type moorer2er19 -reverbTime 10
- *
- * For reverberation times > 30 seconds, the decay seems to fizzle out
- * quite abruptly. The cause is likely caused by single-precision
- * floating point artifacts in the computation of the low-pass filter
- * nested in each comb filter.
- *
- * -noMonoProcess specifies that a reverberator is computed for
- * each input channel. Otherwise, all inputs are
- * summed into a single reverberator. Algorithm
- * types 'comb' and 'allpass' are processed
- * with a feedback gain of opposite polarity in
- * each of two output channels.
- *
- * -reverbTime default is 8 seconds. Applies only to comb,
- * allpass, schroeder2, moorer, moorer2, moorer2er7,
- * moorer2er19 algorithms. Others have decay time
- * as specified in design.
- *
- * -noPrime prevents reciculated delay buffer lengths from
- * quantization to prime value. The "priming"
- * seems to reduce ringing due to transients such
- * as snare drum strike and low-level whining in
- * the presence of input noise, so this parameter
- * is provided for comparison.
- *
- * -type: defaults is moorer2
- *
- * comb, allpass comb and all-pass Interpolated Infinite Impulse
- * Response (IIIR) filters.
- * schroeder1 quint series all-pass filter
- * schroeder2 quad parallel comb into dual series all-pass
- * filters
- * chamberlin quint series all-pass filter
- * moorer Moorer's hex parallel comb filters into single
- * all-pass filter
- * moorer2 hex parallel filtered-comb into single all-pass
- * filters
- * er7, er19 early reflections patterns w/7 and 19 taps,
- * respectively
- * moorer2er7, moorer2er19 early reflections + hex parallel
- * filtered-comb into single all-pass filters.
- * Early reflections fed into comb network.
- * Scatter in 19 tap ER pattern yields algorithm
- * with significantly less ring excited by
- * transients such as snare drum strike.
- *
- * To my ears, moorer2 rings less to transients than moorer2er7,
- * moorer2er19. However, moorer2er7 and moorer2er19 have smoother
- * decay than moorer2. Not sure if ringing is caused by an error
- * in my implementation or by a comb-filter quality imposed by the
- * early reflection pattern. Consider a diffusor other than the
- * early reflection pattern.
- *
- * The following references contain detailed discussions of the
- * non-proprietary implementations found in the code below:
- *
- * + Schroeder, M.R. and Logan, B.F., "'Colorless' Artificial Reverberation."
- * Journal of the Audio Engineering Society v. 9, n. 3: pp. 192-197, 1962
- *
- * + Schroeder, M.R. , "Natural Sounding Artificial Reverberation." Journal
- * of the Audio Engineering Society v. 10, n. 3: pp. 219-223, 1962
- *
- * + Moorer, J.A., "About This Reverberation Business", Foundations of
- * Computer Music, Roads and Strawn, ed.: pp. 605-639, 1985
- *
- * + Chamberlin, Hal, Musical Applications of Microprocessors, 2nd Ed.,
- * Hayden Books, A Division of Howard Sams & Co., Indianapolis, Indiana,
- * pp. 508-512, 1985
- *
- *
- * Written by Gints Klimanis
- * Silicon Graphics Computer Systems
- * 1994
- *********************************************************************** */
- #include <stdio.h>
- #include <audio.h>
- #include <math.h>
- #include <stdlib.h>
- #include <sigfpe.h>
- #include <sys/schedctl.h>
-
- #define FALSE 0
- #define TRUE 1
- #define LEFT 0
- #define RIGHT 1
-
- #define MAX_CHANNELS 2
-
- #define BLOCK_SIZE 512
- #define MAX_DELAY_SIZE 11025
- #define MAX_DELAY_COUNT 30
-
- #define SINGLE_ALL_PASS 0
- #define SINGLE_COMB 1
- #define QUINT_ALL_PASS 2
- #define QUINT_ALL_PASS_STEREO 3
- #define QUAD_COMB_DUAL_ALL_PASS 4
- #define HEX_COMB_ALL_PASS 5
-
- #define SINGLE_ALL_PASS_LPF 10
- #define SINGLE_COMB_LPF 11
- #define HEX_COMB_ALL_PASS_LPF 12
- #define HEX_COMB_ALL_PASS_LPF_ER7 13
- #define HEX_COMB_ALL_PASS_LPF_ER19 14
- #define ER7 15
- #define ER19 16
-
- double samplingRate = 44100;
- float effectLevel = 0.03;
- char effectType = HEX_COMB_ALL_PASS_LPF;
- char stereoize = TRUE;
- char snapToPrime = TRUE; /* seems to reduce some ringing in my tests */
- char monoProcess = TRUE;
- float reverberationTime = 8;
-
- char verboseOperation = FALSE;
-
- typedef struct {
- float *delayLines[MAX_CHANNELS][MAX_DELAY_COUNT],
- *delayOutputs[MAX_CHANNELS][MAX_DELAY_COUNT];
- float inLineDelays[MAX_CHANNELS][MAX_DELAY_COUNT];
- int delayLinePtrs[MAX_CHANNELS][MAX_DELAY_COUNT],
- delayLineLengths[MAX_CHANNELS][MAX_DELAY_COUNT];
- double delayLineTimes[MAX_CHANNELS][MAX_DELAY_COUNT];
- float delayLoopGains[MAX_CHANNELS][MAX_DELAY_COUNT];
- float inLineDelayGains[MAX_CHANNELS][MAX_DELAY_COUNT];
-
- double reverberationTime;
-
- float effectLevel;
-
- char stereoize;
- char snapToPrime;
- } Reverb;
-
- /* high frequency damping coefficients for 25000 & 50000 samples/second */
- float highFrequencyDampingCoeffs_25000Hz[6] = {
- 0.24, 0.26, 0.28, 0.29, 0.30, 0.32};
- float highFrequencyDampingCoeffs_50000Hz[6] = {
- 0.46, 0.48, 0.50, 0.52, 0.53, 0.55};
-
- /*
- * Manfred Schroeder's conditions for artificial reverberators
- * (lifted from paper):
- *
- * 1) The frequency response must be flat when measured with narrow bands
- * of noise, with the bandwidths corresponding to that of the transients
- * in the sound to be reverberated. This condition is, of course,
- * fulfilled by reverberators which have a flat response even for
- * sinusoidal excitation.
- *
- * 2) The normal modes of the reverberator must overlap and cover the entire
- * audio frequency range.
- *
- * 3) The reverberation times of the individual modes must be equal or
- * nearly equal so that different frequency components of the sound will
- * decay with equal rates.
- *
- * 4) The echo density a short interval after shock excitation must be high
- * enough so that individual echos are not resolved by the ear.
- *
- * 5) The echo response must be free from periodicities (flutter echos)
- *
- * 6) The amplitude-frequency response must not exhibit any apparent
- * periodicities. Periodic or comblike frequency responses produce an
- * unpleasant hollow, reedy or metallic sound quality and give the
- * impression that the sound is transmitted through a hollow tube or
- * barrel.
- */
-
- static char applicationUsage[] =
- "\t-help\n\
- \t-verbose\n\
- \t-level 0..1\n\
- \t-noMonoProcess each input processed\n\
- \t-reverbTime seconds\n\
- \t-noPrime\n\
- \t-type {comb, allpass,\n\
- \t schroeder1, schroeder2,\n\
- \t chamberlin,\n\
- \t moorer, moorer2,\n\
- \t er7, er19\n\
- \t moorer2er7, moorer2er19}\n";
-
- long
- GetHardwareInputRate();
- static void
- ParseCommandLine(int argc, char **argv, char fileName[][200]);
- static void
- ProcessParameters(char type, double samplingRate, int channels, Reverb *reverb);
-
- void
- IIIRFloatsLPF(float *input, float *output, int length,
- float *delayLine, int delayLength, int *delayLineIndex, float loopGain,
- float *z, float loopGain2,
- int topology);
- static void
- ConvertDelayLengths(int *lengths, double *times, double samplingRate,
- int count, char snapToPrime);
-
- static void
- MultiTapDelayFloats(float *input, float *output, int length,
- float *delayLine, int delayLength,
- float *tapGains, int *tapIndices, int tapCount);
- int
- IsPrime(int number);
- int
- NearestPrime(int number, int lowerBound, int upperBound);
- int
- UpperPrime(int number, int upperBound);
- int
- LowerPrime(int number, int lowerBound);
- int
- SecondsToSamples(double time, double samplingRate);
- void
- InterleaveNFloatsToShorts(float *inputs[], short *output, int inputLength,
- int interleaveFactor, char saturate);
- void
- DelayFloats(float *in, float *out, long length,
- float *delayBuffer, int delayLength, int *delayBufferPtr,
- char useCircularBuffer);
- void
- CopyFloats(float *in, float *out, int length);
- void
- SumFloats(float *in1, float *in2, float *out, int length);
- void
- ScaleFloats(float *in, float *out, int length, float scaleFactor);
- void
- IIIRFloats(float *in, float *out, int length,
- float *delayLine, int delayLength, int *delayLineIndex,
- float loopGain, int topology);
- void
- SumNFloats(float *inputs[], float *output, int length, int inputChannels);
- void
- DeinterleaveShortsToNFloats(short *input, float *outputs[], int outputLength,
- int interleaveFactor);
- void
- SetFloats(float *in, int length, float value);
-
- /***********************************************************************
- * main()
- *********************************************************************** */
- main(int argc, char **argv)
- {
- int i, j;
- int someInteger;
- char fileName[3][200];
-
- ALport audioInPort, audioOutPort;
- ALconfig aconfig;
-
- short shortBuffer[BLOCK_SIZE*MAX_CHANNELS];
- float *systemInputs[MAX_CHANNELS], *outputs[MAX_CHANNELS];
- float **in, **out;
-
- Reverb *reverb;
- float *gains, *inLineGains;
- int *lengths, *delayLinePtrs;
- int tapCount;
-
- int channelCount, channel;
- int channelsToProcess;
- int delayIndex, delayChannel;
- int iiirType;
- float *inPtr;
-
- float *tmpBuffer[10];
- FILE *inHandle, *outHandle;
- char string[100];
- int priority;
-
- ParseCommandLine(argc, argv, fileName);
-
- /* Prevent OS from intervening w/floating point underflows.
- Set underflowing values to zero */
- sigfpe_[_UNDERFL].repls = _ZERO;
- handle_sigfpes(_ON, _EN_UNDERFL, NULL, _ABORT_ON_ERROR, NULL);
- /* try to schedule at higher priority to prevent drop outs */
- schedctl(NDPRI, 0, NDPNORMMAX);
-
- /* initialize audio system */
- aconfig = ALnewconfig();
- channelCount = MAX_CHANNELS;
- ALsetqueuesize(aconfig, BLOCK_SIZE*10);
- ALsetwidth(aconfig, AL_SAMPLE_16);
- ALsetchannels(aconfig, channelCount);
-
- /* open audio ports w/ALconfiguration */
- audioInPort = ALopenport("xxx", "r", aconfig);
- audioOutPort = ALopenport("xxx", "w", aconfig);
- if ((audioInPort == NULL)||(audioOutPort == NULL))
- {
- fprintf(stderr, "main(): failed to open enough audio ports\n");
- exit(-1);
- }
- ALfreeconfig(aconfig);
- samplingRate = (double) GetHardwareInputRate();
-
-
- /* allocate memory */
- tmpBuffer[0] = (float *) malloc(2*BLOCK_SIZE*sizeof(float));
- tmpBuffer[1] = (float *) malloc(2*BLOCK_SIZE*sizeof(float));
- reverb = (Reverb *) malloc(sizeof(Reverb));
- for (i = 0; i < MAX_CHANNELS; i++)
- {
- systemInputs[i] = (float *) malloc(BLOCK_SIZE*sizeof(float));
- outputs[i] = (float *) malloc(BLOCK_SIZE*sizeof(float));
-
- for (j = 0; j < MAX_DELAY_COUNT; j++)
- {
- reverb->delayOutputs[i][j] = (float *) malloc(BLOCK_SIZE*sizeof(float));
- reverb->delayLines[i][j] = (float *) malloc(MAX_DELAY_SIZE*sizeof(float));
-
- /* clear delay lines */
- reverb->delayLinePtrs[i][j] = 0;
- SetFloats(reverb->delayLines[i][j], MAX_DELAY_SIZE, 0);
- reverb->inLineDelays[i][j] = 0;
- }
- }
-
- /* process effects parameters (after delay line initializations, because
- delay line tap ptrs set up here */
- reverb->stereoize = stereoize;
- reverb->snapToPrime = snapToPrime;
- reverb->reverberationTime = reverberationTime;
- ProcessParameters(effectType, samplingRate, MAX_CHANNELS, reverb);
-
- if (monoProcess == TRUE)
- channelsToProcess = 1;
- else
- channelsToProcess = channelCount;
-
- /* input audio data, process, output */
- while (TRUE)
- {
- ALreadsamps(audioInPort, shortBuffer, BLOCK_SIZE*channelCount);
- if (effectLevel != 0)
- {
- DeinterleaveShortsToNFloats(shortBuffer, systemInputs, BLOCK_SIZE, channelCount);
-
- if (channelsToProcess == 1)
- {
- SumNFloats(systemInputs, tmpBuffer[0], BLOCK_SIZE, channelCount);
- in = &tmpBuffer[0];
- }
- else
- in = systemInputs;
-
- switch (effectType)
- {
- case SINGLE_ALL_PASS:
- case SINGLE_COMB:
- iiirType = 1;
- if (effectType == SINGLE_ALL_PASS)
- iiirType = 3;
-
- for (i = 0; i < channelsToProcess; i++)
- {
- /* compute comb or all-pass filter */
- IIIRFloats(in[i], reverb->delayOutputs[i][0], BLOCK_SIZE,
- reverb->delayLines[i][0], reverb->delayLineLengths[i][0],
- &reverb->delayLinePtrs[i][0], reverb->delayLoopGains[i][0], iiirType);
- ScaleFloats(reverb->delayOutputs[i][0], reverb->delayOutputs[i][0], BLOCK_SIZE, effectLevel);
- }
-
- /* mix processed signal w/input */
- for (i = 0, delayChannel = 0; i < channelCount; i++)
- {
- ScaleFloats(systemInputs[i], systemInputs[i], BLOCK_SIZE, 1-effectLevel);
- SumFloats(reverb->delayOutputs[delayChannel][0], systemInputs[i], outputs[i], BLOCK_SIZE);
-
- if (channelsToProcess > 1)
- delayChannel++;
- }
- break;
-
- case QUINT_ALL_PASS:
- /* compute 5 series all-pass filters */
- for (i = 0; i < channelsToProcess; i++)
- {
- inPtr = in[i];
- for (j = 0; j < 5; j++)
- {
- IIIRFloats(inPtr, reverb->delayOutputs[i][j], BLOCK_SIZE,
- reverb->delayLines[i][j], reverb->delayLineLengths[i][j],
- &reverb->delayLinePtrs[i][j], reverb->delayLoopGains[i][j], 3);
- inPtr = reverb->delayOutputs[i][j];
- }
-
- ScaleFloats(reverb->delayOutputs[i][j-1], reverb->delayOutputs[i][j-1], BLOCK_SIZE, effectLevel);
- }
-
- /* mix processed signal w/input */
- for (i = 0, delayChannel = 0; i < channelCount; i++)
- {
- ScaleFloats(systemInputs[i], systemInputs[i], BLOCK_SIZE, 1-effectLevel);
- SumFloats(reverb->delayOutputs[delayChannel][j-1], systemInputs[i], outputs[i], BLOCK_SIZE);
-
- if (channelsToProcess > 1)
- delayChannel++;
- }
- break;
-
- case QUINT_ALL_PASS_STEREO:
- /* compute 5 series all-pass filters */
- for (i = 0; i < channelsToProcess; i++)
- {
- inPtr = in[i];
- for (j = 0; j < 5; j++)
- {
- IIIRFloats(inPtr, reverb->delayOutputs[i][j], BLOCK_SIZE,
- reverb->delayLines[i][j], reverb->delayLineLengths[i][j],
- &reverb->delayLinePtrs[i][j], reverb->delayLoopGains[i][j], 3);
- inPtr = reverb->delayOutputs[i][j];
- }
-
- ScaleFloats(reverb->delayOutputs[i][j-1], reverb->delayOutputs[i][j-1], BLOCK_SIZE, effectLevel);
- }
-
- /* mix processed signal w/input */
- for (i = 0, delayChannel = 0; i < channelCount; i++)
- {
- ScaleFloats(systemInputs[i], systemInputs[i], BLOCK_SIZE, 1-effectLevel);
- SumFloats(reverb->delayOutputs[delayChannel][j-1], systemInputs[i], outputs[i], BLOCK_SIZE);
-
- if (channelsToProcess > 1)
- delayChannel++;
- }
- break;
-
- case QUAD_COMB_DUAL_ALL_PASS:
- for (i = 0; i < channelsToProcess; i++)
- {
- /* compute 4 parallel comb filters & sum*/
- for (j = 0; j < 4; j++)
- IIIRFloats(in[i], reverb->delayOutputs[i][j], BLOCK_SIZE,
- reverb->delayLines[i][j], reverb->delayLineLengths[i][j],
- &reverb->delayLinePtrs[i][j], reverb->delayLoopGains[i][j], 1);
- SumNFloats(reverb->delayOutputs[i], reverb->delayOutputs[i][j-1], BLOCK_SIZE, j);
-
- /* pass sum thru 2 series all-pass filters */
- for (; j < 6; j++)
- IIIRFloats(reverb->delayOutputs[i][j-1], reverb->delayOutputs[i][j], BLOCK_SIZE,
- reverb->delayLines[i][j], reverb->delayLineLengths[i][j],
- &reverb->delayLinePtrs[i][j], reverb->delayLoopGains[i][j], 3);
-
- ScaleFloats(reverb->delayOutputs[i][j-1], reverb->delayOutputs[i][j-1], BLOCK_SIZE, effectLevel);
- }
-
- /* mix processed signal w/input */
- for (i = 0, delayChannel = 0; i < channelCount; i++)
- {
- ScaleFloats(systemInputs[i], systemInputs[i], BLOCK_SIZE, 1-effectLevel);
- SumFloats(reverb->delayOutputs[delayChannel][j-1], systemInputs[i], outputs[i], BLOCK_SIZE);
-
- if (channelsToProcess > 1)
- delayChannel++;
- }
- break;
-
- case HEX_COMB_ALL_PASS:
- for (i = 0; i < channelsToProcess; i++)
- {
- /* compute 6 parallel comb filters & sum */
- for (j = 0; j < 6; j++)
- IIIRFloats(in[i], reverb->delayOutputs[i][j], BLOCK_SIZE,
- reverb->delayLines[i][j], reverb->delayLineLengths[i][j],
- &reverb->delayLinePtrs[i][j], reverb->delayLoopGains[i][j], 1);
- SumNFloats(reverb->delayOutputs[i], reverb->delayOutputs[i][j-1], BLOCK_SIZE, j);
-
- /* pass sum thru single all-pass filter */
- IIIRFloats(reverb->delayOutputs[i][j-1], reverb->delayOutputs[i][j], BLOCK_SIZE,
- reverb->delayLines[i][j], reverb->delayLineLengths[i][j],
- &reverb->delayLinePtrs[i][j], reverb->delayLoopGains[i][j], 3);
-
- ScaleFloats(reverb->delayOutputs[i][j], reverb->delayOutputs[i][j], BLOCK_SIZE, effectLevel);
- }
-
- /* mix processed signal w/input */
- for (i = 0, delayChannel = 0; i < channelCount; i++)
- {
- ScaleFloats(systemInputs[i], systemInputs[i], BLOCK_SIZE, 1-effectLevel);
- SumFloats(reverb->delayOutputs[delayChannel][j], systemInputs[i], outputs[i], BLOCK_SIZE);
-
- if (channelsToProcess > 1)
- delayChannel++;
- }
- break;
-
- case ER7:
- case ER19:
- for (i = 0; i < channelsToProcess; i++)
- {
- /* compute early reflection pattern */
- tapCount = 7;
- if (effectType == ER19)
- tapCount = 19;
- MultiTapDelayFloats(in[i], reverb->delayOutputs[i][0], BLOCK_SIZE,
- reverb->delayLines[i][0], reverb->delayLineLengths[i][tapCount-1]+1,
- reverb->delayLoopGains[i], reverb->delayLinePtrs[i], tapCount);
- }
-
- /* mix processed signal w/input */
- for (i = 0, delayChannel = 0; i < channelCount; i++)
- {
- CopyFloats(reverb->delayOutputs[delayChannel][0], outputs[i], BLOCK_SIZE);
- if (channelsToProcess > 1)
- delayChannel++;
- }
- break;
-
- case HEX_COMB_ALL_PASS_LPF:
- for (i = 0; i < channelsToProcess; i++)
- {
- /* compute 6 parallel comb filters & sum */
- for (j = 0; j < 6; j++)
- IIIRFloatsLPF(in[i], reverb->delayOutputs[i][j], BLOCK_SIZE,
- reverb->delayLines[i][j], reverb->delayLineLengths[i][j],
- &reverb->delayLinePtrs[i][j], reverb->delayLoopGains[i][j],
- &reverb->inLineDelays[i][j], reverb->inLineDelayGains[i][j], 1);
- SumNFloats(reverb->delayOutputs[i], reverb->delayOutputs[i][j-1], BLOCK_SIZE, j);
-
- /* pass sum thru single all-pass filter */
- IIIRFloats(reverb->delayOutputs[i][j-1], reverb->delayOutputs[i][j], BLOCK_SIZE,
- reverb->delayLines[i][j], reverb->delayLineLengths[i][j],
- &reverb->delayLinePtrs[i][j], reverb->delayLoopGains[i][j], 3);
-
- ScaleFloats(reverb->delayOutputs[i][j], reverb->delayOutputs[i][j], BLOCK_SIZE, effectLevel);
- }
-
- /* mix processed signal w/input */
- for (i = 0, delayChannel = 0; i < channelCount; i++)
- {
- ScaleFloats(systemInputs[i], systemInputs[i], BLOCK_SIZE, 1-effectLevel);
- SumFloats(reverb->delayOutputs[delayChannel][j], systemInputs[i], outputs[i], BLOCK_SIZE);
-
- if (channelsToProcess > 1)
- delayChannel++;
- }
- break;
-
- case HEX_COMB_ALL_PASS_LPF_ER7:
- case HEX_COMB_ALL_PASS_LPF_ER19:
- for (i = 0; i < channelsToProcess; i++)
- {
- /* compute early reflection pattern */
- tapCount = 19;
- if (effectType == HEX_COMB_ALL_PASS_LPF_ER7)
- tapCount = 7;
- MultiTapDelayFloats(in[i], reverb->delayOutputs[i][7], BLOCK_SIZE,
- reverb->delayLines[i][7], reverb->delayLineLengths[i][7+tapCount-1]+1,
- &reverb->delayLoopGains[i][7], &reverb->delayLinePtrs[i][7], tapCount);
-
- /* compute 6 parallel comb filters & sum */
- for (j = 0; j < 6; j++)
- IIIRFloatsLPF(reverb->delayOutputs[i][7], reverb->delayOutputs[i][j], BLOCK_SIZE,
- reverb->delayLines[i][j], reverb->delayLineLengths[i][j],
- &reverb->delayLinePtrs[i][j], reverb->delayLoopGains[i][j],
- &reverb->inLineDelays[i][j], reverb->inLineDelayGains[i][j], 1);
- SumNFloats(reverb->delayOutputs[i], reverb->delayOutputs[i][5], BLOCK_SIZE, 6);
-
- /* pass sum thru single all-pass filter */
- IIIRFloats(reverb->delayOutputs[i][5], reverb->delayOutputs[i][6], BLOCK_SIZE,
- reverb->delayLines[i][6], reverb->delayLineLengths[i][6],
- &reverb->delayLinePtrs[i][6], reverb->delayLoopGains[i][6], 3);
-
- #define LATE_DELAY 7+tapCount
- /* delay late reflections */
- DelayFloats(reverb->delayOutputs[i][6], reverb->delayOutputs[i][LATE_DELAY], BLOCK_SIZE,
- reverb->delayLines[i][LATE_DELAY], reverb->delayLineLengths[i][LATE_DELAY],
- &reverb->delayLinePtrs[i][LATE_DELAY], FALSE);
-
- /* add delayed late reflections to early reflections */
- SumFloats(reverb->delayOutputs[i][LATE_DELAY], reverb->delayOutputs[i][7],
- reverb->delayOutputs[i][LATE_DELAY], BLOCK_SIZE);
- ScaleFloats(reverb->delayOutputs[i][LATE_DELAY], reverb->delayOutputs[i][LATE_DELAY], BLOCK_SIZE, effectLevel);
- }
-
- /* mix processed signal w/input */
- for (i = 0, delayChannel = 0; i < channelCount; i++)
- {
- ScaleFloats(systemInputs[i], systemInputs[i], BLOCK_SIZE, 1-effectLevel);
- SumFloats(reverb->delayOutputs[delayChannel][LATE_DELAY], systemInputs[i], outputs[i], BLOCK_SIZE);
- if (channelsToProcess > 1)
- delayChannel++;
- }
-
- break;
-
- default:
- break;
- }
-
- InterleaveNFloatsToShorts(outputs, shortBuffer, BLOCK_SIZE, channelCount, TRUE);
- }
-
- ALwritesamps(audioOutPort, shortBuffer, BLOCK_SIZE*channelCount);
- }
-
- /* release audio ports */
- ALcloseport(audioInPort);
- ALcloseport(audioOutPort);
- } /* ------------------ end main() --------------- */
-
- /*
- * GetHardwareInputRate: acquire audio hardware input sampling rate
- * -------------------------------------------------------------------- */
- long
- GetHardwareInputRate()
- {
- long buffer[6];
-
- /* acquire state variables of audio hardware */
- buffer[0] = AL_INPUT_RATE;
- buffer[2] = AL_INPUT_SOURCE;
- buffer[4] = AL_DIGITAL_INPUT_RATE;
- ALgetparams(AL_DEFAULT_DEVICE, buffer, 6);
-
- /* for input sources microphone or line and input rate not AES word clock */
- if ((buffer[3] != AL_INPUT_DIGITAL)&&(buffer[1] > 0))
- return (buffer[1]);
-
- /* for input rate AES word clock and machine has ability to read digital input sampling rate, return
- AL_DIGITAL_INPUT_RATE */
- else if (ALgetdefault(AL_DEFAULT_DEVICE, AL_DIGITAL_INPUT_RATE) >= 0)
- return (buffer[5]);
-
- /* could not determine sampling rate */
- else
- return (AL_RATE_UNDEFINED);
- } /* ------------------------- end GetHardwareInputRate() -------------------------- */
-
- /* **********************************************************************
- * ParseCommandLine: parse input command line for user options
- * ********************************************************************** */
- static void
- ParseCommandLine(int argc, char **argv, char fileName[][200])
- {
- int i;
-
- for (i = 1; i < argc; i++)
- {
- /* check for -h or -help */
- if ((!strcmp(argv[i], "-h"))||(!strcmp(argv[i], "-help")))
- {
- fprintf(stderr, "Usage: %s\n", applicationUsage);
- exit(1);
- }
-
- /* check for -verbose */
- else if ((!strcmp(argv[i], "-v"))||(!strcmp(argv[i], "-verbose")))
- {
- verboseOperation = TRUE;
- }
-
- /* check for -noMonoProcess */
- else if (!strcmp(argv[i], "-noMonoProcess"))
- {
- monoProcess = FALSE;
- }
-
- /* check for -noPrime */
- else if (!strcmp(argv[i], "-noPrime"))
- {
- snapToPrime = FALSE;
- }
-
- /* check for reverbTime */
- else if (!strcmp(argv[i], "-reverbTime"))
- {
- i++;
- if (i < argc)
- {
- reverberationTime = atof(argv[i]);
- if (reverberationTime < 0)
- {
- fprintf(stderr, "Bogus %s: %s\n", argv[i-1], argv[i]);
- exit(1);
- }
- }
- else
- {
- fprintf(stderr, "Usage: %s\n", applicationUsage);
- exit(1);
- }
- }
-
- /* check for effectLevel */
- else if (!strcmp(argv[i], "-level"))
- {
- i++;
- if (i < argc)
- {
- effectLevel = atof(argv[i]);
- if (effectLevel < 0)
- {
- fprintf(stderr, "Bogus %s: %s\n", argv[i-1], argv[i]);
- exit(1);
- }
- }
- else
- {
- fprintf(stderr, "Usage: %s\n", applicationUsage);
- exit(1);
- }
- }
-
- /* check for effect type */
- else if (!strcmp(argv[i], "-type"))
- {
- i++;
- if (i < argc)
- {
- if (!strcmp(argv[i], "schroeder1"))
- effectType = QUINT_ALL_PASS;
- else if (!strcmp(argv[i], "schroeder2"))
- effectType = QUAD_COMB_DUAL_ALL_PASS;
-
- else if (!strcmp(argv[i], "chamberlin"))
- effectType = QUINT_ALL_PASS_STEREO;
-
- else if (!strcmp(argv[i], "moorer"))
- effectType = HEX_COMB_ALL_PASS;
- else if (!strcmp(argv[i], "moorer2"))
- effectType = HEX_COMB_ALL_PASS_LPF;
-
- else if (!strcmp(argv[i], "er7"))
- effectType = ER7;
- else if (!strcmp(argv[i], "er19"))
- effectType = ER19;
- else if (!strcmp(argv[i], "moorer2er7"))
- effectType = HEX_COMB_ALL_PASS_LPF_ER7;
- else if (!strcmp(argv[i], "moorer2er19"))
- effectType = HEX_COMB_ALL_PASS_LPF_ER19;
-
- else if (!strcmp(argv[i], "comb"))
- effectType = SINGLE_COMB;
- else if (!strcmp(argv[i], "allpass"))
- effectType = SINGLE_ALL_PASS;
-
- else
- {
- fprintf(stderr, "Bogus %s: %s\n", argv[i-1], argv[i]);
- exit(1);
- }
- }
- else
- {
- fprintf(stderr, "Usage: %s\n", applicationUsage);
- exit(1);
- }
- }
-
- /* oh, error */
- else
- {
- fprintf(stderr, "Usage: %s\n", applicationUsage);
- exit(1);
- }
- }
- } /* ----------------------- end ParseCommandLine() --------------------- */
-
- /* **********************************************************************
- * ProcessParameters: parse input command line for user options
- * ********************************************************************** */
- static void
- ProcessParameters(char type, double samplingRate, int channels, Reverb *reverb)
- /*
- type algorithm type
- samplingRate sampling rate
- channels # processing channels
- reverb ptr to parameter structure
- */
- {
- int i, j, k;
- float hiCoeff, loCoeff;
- double *times;
- float *gains, *inLineGains;
- int *lengths, *delayLinePtrs;
- int channel;
- int value;
- double reverberationTime;
- int tapCount;
- int maxLength;
- double times_er[19], gains_er[19];
- int earlyToLateReflectionAlignmentLength;
-
- reverberationTime = reverb->reverberationTime;
-
- /* initialize early reflections parameters */
- if ((type == ER7)||(type == HEX_COMB_ALL_PASS_LPF_ER7))
- {
- times_er[0] = 0; gains_er[0] = 1;
- times_er[1] = 0.0199; gains_er[1] = 1.02;
- times_er[2] = 0.0354; gains_er[2] = 0.818;
- times_er[3] = 0.0389; gains_er[3] = 0.635;
- times_er[4] = 0.0414; gains_er[4] = 0.719;
- times_er[5] = 0.0699; gains_er[5] = 0.267;
- times_er[6] = 0.0796; gains_er[6] = 0.242;
- }
- else if ((type == ER19)||(type == HEX_COMB_ALL_PASS_LPF_ER19))
- {
- times_er[0] = 0; gains_er[0] = 1;
- times_er[1] = 0.0043; gains_er[1] = 0.841;
- times_er[2] = 0.0215; gains_er[2] = 0.504;
- times_er[3] = 0.0225; gains_er[3] = 0.491;
- times_er[4] = 0.0268; gains_er[4] = 0.379;
- times_er[5] = 0.0270; gains_er[5] = 0.380;
- times_er[6] = 0.0298; gains_er[6] = 0.346;
- times_er[7] = 0.0458; gains_er[7] = 0.289;
- times_er[8] = 0.0485; gains_er[8] = 0.272;
- times_er[9] = 0.0572; gains_er[9] = 0.192;
- times_er[10] = 0.0587; gains_er[10] = 0.193;
- times_er[11] = 0.0595; gains_er[11] = 0.217;
- times_er[12] = 0.0612; gains_er[12] = 0.181;
- times_er[13] = 0.0707; gains_er[13] = 0.180;
- times_er[14] = 0.0708; gains_er[14] = 0.181;
- times_er[15] = 0.0726; gains_er[15] = 0.176;
- times_er[16] = 0.0741; gains_er[16] = 0.142;
- times_er[17] = 0.0753; gains_er[17] = 0.167;
- times_er[18] = 0.0797; gains_er[18] = 0.134;
- }
-
- /*
- * initialize reverberation parameters according to algorithm
- */
- switch (type)
- {
- case SINGLE_COMB:
- case SINGLE_ALL_PASS:
- for (channel = 0; channel < channels; channel++)
- {
- times = reverb->delayLineTimes[channel];
- gains = reverb->delayLoopGains[channel];
- lengths = reverb->delayLineLengths[channel];
-
- times[0] = 0.100;
- gains[0] = pow(10, -3*times[0]/reverberationTime);
-
- /* place opposite gain polarities in adjacent channels for stereo effect */
- if (((i&1) == 0)&&(reverb->stereoize == TRUE))
- gains[0] = -gains[0];
-
- ConvertDelayLengths(lengths, times, samplingRate, 1, reverb->snapToPrime);
- }
- break;
-
- case QUINT_ALL_PASS:
- for (channel = 0; channel < channels; channel++)
- {
- times = reverb->delayLineTimes[channel];
- gains = reverb->delayLoopGains[channel];
- lengths = reverb->delayLineLengths[channel];
-
- times[0] = 0.100;
- times[1] = 0.068;
- times[2] = 0.060;
- times[3] = 0.0197;
- times[4] = 0.00585;
-
- gains[0] = 0.7;
- gains[1] = -0.7;
- gains[2] = 0.7;
- gains[3] = 0.7;
- gains[4] = 0.7;
-
- ConvertDelayLengths(lengths, times, samplingRate, 5, reverb->snapToPrime);
- }
- break;
-
- case QUINT_ALL_PASS_STEREO:
- for (channel = 0; channel < channels; channel++)
- {
- times = reverb->delayLineTimes[channel];
- gains = reverb->delayLoopGains[channel];
- lengths = reverb->delayLineLengths[channel];
-
- times[0] = 0.0496;
- times[1] = 0.03465;
- times[2] = 0.02418;
-
- gains[0] = 0.75;
- gains[1] = 0.72;
- gains[2] = 0.691;
-
- /* use Lauridsen effect for stereoization */
- if ((i&1) == 0)
- {
- times[3] = 0.01785;
- times[4] = 0.01098;
- gains[3] = 0.649;
- gains[4] = 0.662;
- }
- else
- {
- times[3] = 0.01801;
- times[4] = 0.01082;
- gains[3] = 0.646;
- gains[4] = 0.666;
- }
-
- ConvertDelayLengths(lengths, times, samplingRate, 5, reverb->snapToPrime);
- }
-
- break;
-
- case QUAD_COMB_DUAL_ALL_PASS:
- for (channel = 0; channel < channels; channel++)
- {
- times = reverb->delayLineTimes[channel];
- gains = reverb->delayLoopGains[channel];
- lengths = reverb->delayLineLengths[channel];
-
- /* comb filters (shortest = predelay: time between direct sound and reverb) */
- times[0] = 0.045;
- times[1] = 0.040;
- times[2] = 0.035;
- times[3] = 0.030;
-
- /* comb filters: gain = 10^(-3*delayTime/reverberationTime) */
- for (j = 0; j < 4; j++)
- gains[j] = pow(10, -3*times[j]/reverberationTime);
-
- /* all-pass filters */
- times[4] = 0.005;
- gains[4] = 0.7;
- times[5] = 0.0017;
- gains[5] = 0.7;
-
- ConvertDelayLengths(lengths, times, samplingRate, 6, reverb->snapToPrime);
- }
- break;
-
- case HEX_COMB_ALL_PASS:
- case HEX_COMB_ALL_PASS_LPF:
- for (channel = 0; channel < channels; channel++)
- {
- times = reverb->delayLineTimes[channel];
- gains = reverb->delayLoopGains[channel];
- lengths = reverb->delayLineLengths[channel];
- inLineGains = reverb->inLineDelayGains[channel];
-
- /* comb filters (shortest = predelay: time between direct sound and reverb) */
- times[0] = 0.050;
- times[1] = 0.056;
- times[2] = 0.061;
- times[3] = 0.068;
- times[4] = 0.072;
- times[5] = 0.078;
-
- /* comb filters: gain = 10^(-3*delayTime/reverberationTime) */
- /* gain = 10^(-3*delayTime/reverberationTime) but moorer sets all to same gain
- with time 0.050 seconds */
- for (j = 0; j < 6; j++)
- gains[j] = pow(10, -3*0.050/reverberationTime);
-
- /* all-pass filters */
- times[6] = 0.006;
- gains[6] = 0.7;
-
- if (type == HEX_COMB_ALL_PASS_LPF)
- {
- /* in-loop low pass filter coefficients */
- /* linearly interpolate new point from 2 tables at 25000 & 50000 Hz
- y = y0 + (x-x0)*(y1-y0)/(x1-x0) */
- for (i = 0; i < 6; i++)
- {
- hiCoeff = highFrequencyDampingCoeffs_50000Hz[i];
- loCoeff = highFrequencyDampingCoeffs_25000Hz[i];
- inLineGains[i] = loCoeff +
- (samplingRate - 25000)*(hiCoeff - loCoeff)/(50000 - 25000);
-
- /* force to stability condition: g2/(1-g1) < 1 --> g2 = g(1 - g1) */
- /* gains[j] = (1 - inLineGains[j])*pow(10, -3*times[j]/reverberationTime);*/
- gains[i] *= (1 - inLineGains[i]);
- }
- }
-
- ConvertDelayLengths(lengths, times, samplingRate, 7, reverb->snapToPrime);
- }
- break;
-
- case ER7:
- case ER19:
- for (channel = 0; channel < channels; channel++)
- {
- times = reverb->delayLineTimes[channel];
- gains = reverb->delayLoopGains[channel];
- lengths = reverb->delayLineLengths[channel];
- delayLinePtrs = reverb->delayLinePtrs[channel];
-
- if (type == ER7)
- tapCount = 7;
- else
- tapCount = 19;
- for (i = 0; i < tapCount; i++)
- {
- times[i] = times_er[i];
- gains[i] = gains_er[i];
- }
- ConvertDelayLengths(lengths, times, samplingRate, tapCount, FALSE);
-
- /* initialize tap ptrs. Longest tap assumed to be last tap */
- delayLinePtrs[i] = 0;
- maxLength = lengths[tapCount-1];
- for (i = 1; i < tapCount; i++)
- delayLinePtrs[i] = 1 + maxLength - lengths[i];
- }
- break;
-
- case HEX_COMB_ALL_PASS_LPF_ER7:
- case HEX_COMB_ALL_PASS_LPF_ER19:
- for (channel = 0; channel < channels; channel++)
- {
- times = reverb->delayLineTimes[channel];
- gains = reverb->delayLoopGains[channel];
- lengths = reverb->delayLineLengths[channel];
- inLineGains = reverb->inLineDelayGains[channel];
- delayLinePtrs = reverb->delayLinePtrs[channel];
-
- /*
- * LATE REFLECTION PATTERN
- */
- /* comb filters (shortest = predelay: time between direct sound and reverb) */
- times[0] = 0.050;
- times[1] = 0.056;
- times[2] = 0.061;
- times[3] = 0.068;
- times[4] = 0.072;
- times[5] = 0.078;
-
- /* all-pass filter */
- times[6] = 0.006;
- gains[6] = 0.7;
-
- for (i = 0; i < 6; i++)
- {
- /* comb filters: gain = 10^(-3*delayTime/reverberationTime) */
- /* gain = 10^(-3*delayTime/reverberationTime) (Moorer sets all to same gain) */
- /* gain = (1 - inLineGain)*pow(10, -3*time/reverberationTime);*/
- gains[i] = pow(10, -3*0.05/reverberationTime);
-
- /* in-loop low pass filter coefficients */
- /* linearly interpolate new point from 25000 & 50000 Hz tables */
- /*y = y0 + (x-x0)*(y1-y0)/(x1-x0) */
- hiCoeff = highFrequencyDampingCoeffs_50000Hz[i];
- loCoeff = highFrequencyDampingCoeffs_25000Hz[i];
- inLineGains[i] = loCoeff +
- (samplingRate - 25000)*(hiCoeff - loCoeff)/(50000 - 25000);
-
- /* force to stability condition: g2/(1-g1) < 1 --> g2 = g(1 - g1) */
- gains[i] *= (1 - inLineGains[i]);
- }
-
- ConvertDelayLengths(lengths, times, samplingRate, 7, reverb->snapToPrime);
-
- /*
- * EARLY REFLECTION PATTERN
- */
- tapCount = 7;
- if (type == HEX_COMB_ALL_PASS_LPF_ER19)
- tapCount = 19;
- times += 7;
- gains += 7;
- lengths += 7;
- delayLinePtrs += 7;
-
- for (i = 0; i < tapCount; i++)
- {
- times[i] = times_er[i];
- gains[i] = gains_er[i];
- }
-
- ConvertDelayLengths(lengths, times, samplingRate, tapCount, FALSE);
-
- /* align last tap of ER generator lands close to first echo from
- late reflection by adding delay to late reflections
- alignment delay = ER longest delay - LR shortest comb delay
-
- assume last ER delay is longer than shortest LR comb delay, as is
- case for 7 and 19 tap ER generators
- */
- lengths[tapCount] = lengths[tapCount-1] - lengths[-7];
-
- /* initialize tap ptrs. Longest tap assumed to be last tap */
- delayLinePtrs[i] = 0;
- maxLength = lengths[tapCount-1];
- for (i = 0; i < tapCount; i++)
- delayLinePtrs[i] = 1 + maxLength - lengths[i];
- }
- break;
-
- default:
- printf("ProcessParameters(): bogus type: %d\n", type);
- break;
- }
-
-
-
- times = reverb->delayLineTimes[0];
- gains = reverb->delayLoopGains[0];
- lengths = reverb->delayLineLengths[0];
- inLineGains = reverb->inLineDelayGains[0];
- delayLinePtrs = reverb->delayLinePtrs[0];
-
- #ifdef SAFE
- for (i = 0; i < 30; i++)
- printf("%d: t=%f, g=%f, ig=%f, l=%d\n", i, times[i], gains[i], inLineGains[i], lengths[i]);
- #endif
- } /* ----------------------- end ProcessParameters() --------------------- */
-
- /* **********************************************************************
- * IIIRFloatsLPF: interpolated IIR (comb/all-pass) w/low pass filter
- * ********************************************************************** */
- void
- IIIRFloatsLPF(float *input, float *output, int length,
- float *delayLine, int delayLength, int *delayLineIndex, float loopGain,
- float *inLoopDelay, float inLoopGain,
- int topology)
- /* input ptr to input buffer
- output ptr to output buffer
- length length of input buffer
- delayLine ptr to delay line
- delayLength length of delay buffer
- delayLineIndex ptr to index of next read/write position in delay buffer.
- loopGain feedback gain
- inLoopDelay in-loop IIR filter delay element
- inLoopGain in-loop IIR filter coefficient
- topology 0: comb filter, input not delayed
- 1: comb filter, input delayed
- 2: comb filter, input delayed, scaled
- 3: all-pass filter,
- 4: all-pass filter, one multiply
- */
- {
- int i;
- int delayIndex;
- float y, sum;
- float z;
-
- delayIndex = *delayLineIndex;
- z = *inLoopDelay;
-
- switch (topology)
- {
- /* comb filter: input delayed, IIR low-pass filter in loop */
- /* -m -m
- z z
- H(z) = --------------- = ------------
- -m -m
- 1 - g*T(z)*z 1 - g*z
- ---------
- -1
- 1 - g1*z
-
- where T(z) = 1/(1 - g1*(z^-1))
- */
- case 1:
- for (i = 0; i < length; i++)
- {
- y = delayLine[delayIndex];
- output[i] = y;
-
- /* update delay elements */
- y += z*inLoopGain;
- delayLine[delayIndex++] = input[i] + y*loopGain;
- if (delayIndex >= delayLength)
- delayIndex = 0;
- z = y;
- }
- break;
-
- default:
- fprintf(stderr, "IIIRFloatsLPF(): bogus topology: %d\n", topology);
- break;
- }
-
- *inLoopDelay = z;
- *delayLineIndex = delayIndex;
- } /* ----------------------- end IIIRFloatsLPF() --------------------- */
-
- /* **********************************************************************
- * MultiTapDelayFloats: interpolated IIR (comb/all-pass) w/low pass filter
- * ********************************************************************** */
- static void
- MultiTapDelayFloats(float *input, float *output, int length,
- float *delayLine, int delayLength,
- float *tapGains, int *tapIndices, int tapCount)
- /* input ptr to input buffer
- output ptr to output buffer
- length length of input buffer
- delayLine ptr to delay line
- delayLength length of longest tap
-
- tapGains ptr to delay line tap gains
- tapIndices ptr to delay line tap indices
- tapCount # taps
- */
- {
- int i, tap, tapIndex;
- float sum;
-
- /* sum taps, advance and bind tap ptrs. In anticipation of conditional move
- instruction, change code to decrement counter and wrap at 0 rather than
- increment and wrap at 'delayLength' */
- for (i = 0; i < length; i++)
- {
- delayLine[tapIndices[0]] = input[i];
- for (tap = 0, sum = 0; tap < tapCount; tap++)
- {
- sum += tapGains[tap]*delayLine[tapIndices[tap]++];
- if (tapIndices[tap] >= delayLength)
- tapIndices[tap] = 0;
- }
- output[i] = sum;
- }
- } /* ----------------------- end MultiTapDelayFloats() --------------------- */
-
- /* **********************************************************************
- * ConvertDelayLengths: convert delay times to delay lengths
- * ********************************************************************** */
- static void
- ConvertDelayLengths(int *lengths, double *times, double samplingRate,
- int count, char snapToPrime)
- /*
- */
- {
- int i;
-
- for (i = 0; i < count; i++)
- {
- lengths[i] = SecondsToSamples(times[i], samplingRate);
- if (snapToPrime == TRUE)
- {
- lengths[i] = NearestPrime(lengths[i], 2, 10000);
- }
- }
- } /* ----------------------- end ConvertDelayLengths() --------------------- */
-
- /****************************************************************
- * SetFloats fill buffer w/'value' FLOATs
- *****************************************************************/
- void
- SetFloats(float *in, int length, float value)
- /* in ptr to input data
- length length of data
- value value to fill buffer
- */
- {
- register int i;
- for (i = 0; i < length; i++)
- in[i] = value;
- } /* ------------------ end SetFloats() --------------- */
-
- /* **************************************************************
- * DeinterleaveShortsToNFloats deinterleave to N buffers
- *
- * The first word of input buffer at 'input'
- * will be first word in output buffer 'outputLeft.'
- *****************************************************************/
- void
- DeinterleaveShortsToNFloats(short *input, float *outputs[], int outputLength,
- int interleaveFactor)
- /* input ptr to input buffer
- outputs ptr to array of output buffers
- outputLength length of output buffer
- interleaveFactor # output buffers (interleave factor)
- */
- {
- register int i, j;
- register short *in;
-
- /* deinterleave of N-sample frames */
- in = input;
- for (i = 0; i < outputLength; i++)
- {
- for (j = 0; j < interleaveFactor; j++)
- outputs[j][i] = (float) in[j];
- in += interleaveFactor;
- }
- } /* ------------------ end DeinterleaveShortsToNFloats() --------------- */
-
- /****************************************************************
- * SumNFloats sum N buffers
- *****************************************************************/
- void
- SumNFloats(float *inputs[], float *output, int length, int inputChannels)
- /* inputs ptr to array of input buffers
- output ptr to output buffer
- length length of buffers
- inputChannels #channels to be summed
- */
- {
- register int i, j;
- register float sum;
-
- for (i = 0; i < length; i++)
- {
- sum = 0;
- for (j = 0; j < inputChannels; j++)
- sum += inputs[j][i];
- output[i] = sum;
- }
- } /* ------------------ end SumNFloats() --------------- */
-
- /* **********************************************************************
- * IIIRFloats: interpolated IIR (comb/all-pass)
- * ********************************************************************** */
- void
- IIIRFloats(float *in, float *out, int length,
- float *delayLine, int delayLength, int *delayLineIndex,
- float loopGain, int topology)
- /* in ptr to input buffer
- out ptr to output buffer
- length length of input buffer
- delayLine ptr to delay line
- delayLength length of delay buffer
- delayLineIndex ptr to index of next read/write position in delay buffer.
- loopGain feedback gain
- topology 0: comb filter, input not delayed
- 1: comb filter, input delayed
- 2: comb filter, input delayed, scaled
- 3: all-pass filter,
- 4: all-pass filter, one multiply
- */
- {
- int i;
- int delayIndex;
- float y, sum;
-
- delayIndex = *delayLineIndex;
-
- /*
- comb filter magnitude response:
-
- gain at maxima = 1/(1-loopGain)
- gain at minima = 1/(1+loopGain)
-
- comb period = 1/delayLength
- */
- switch (topology)
- {
- /* comb filter: input not delayed */
- /*
- 1
- H(z) = ----------
- -m
- 1 - g*z
- */
- case 0:
- for (i = 0; i < length; i++)
- {
- y = in[i] + delayLine[delayIndex]*loopGain;
- out[i] = y;
-
- delayLine[delayIndex++] = y;
- if (delayIndex >= delayLength)
- delayIndex = 0;
- }
- break;
-
- /* comb filter: input delayed */
- /* -m
- z
- H(z) = ----------
- -m
- 1 - g*z
- */
- case 1:
- for (i = 0; i < length; i++)
- {
- y = delayLine[delayIndex];
- out[i] = y;
- delayLine[delayIndex++] = in[i] + y*loopGain;
- if (delayIndex >= delayLength)
- delayIndex = 0;
- }
- break;
-
- /* comb filter: input delayed, scaled */
- case 2:
- for (i = 0; i < length; i++)
- {
- y = delayLine[delayIndex]*loopGain;
- out[i] = y;
- delayLine[delayIndex++] = in[i] + y;
- if (delayIndex >= delayLength)
- delayIndex = 0;
- }
- break;
-
- /* all-pass filter */
- /* -m
- g + z
- H(z) = ----------
- -m
- 1 + g*z
- */
- case 3:
- for (i = 0; i < length; i++)
- {
- y = delayLine[delayIndex];
- out[i] = y - in[i]*loopGain;
- delayLine[delayIndex++] = y*loopGain + in[i];
- if (delayIndex >= delayLength)
- delayIndex = 0;
- }
- break;
-
- /* one multiply all-pass filter */
- /* -m
- g + z
- H(z) = ----------
- -m
- 1 + g*z
- */
- case 4:
- for (i = 0; i < length; i++)
- {
- y = delayLine[delayIndex];
- sum = (in[i] - y)*loopGain;
-
- out[i] = sum + y;
- delayLine[delayIndex++] = sum + in[i];
- if (delayIndex >= delayLength)
- delayIndex = 0;
- }
- break;
- default:
- fprintf(stderr, "IIIRFloats(): bogus topology: %d\n", topology);
- break;
- }
- *delayLineIndex = delayIndex;
- } /* ----------------------- end IIIRFloats() --------------------- */
-
- /****************************************************************
- * ScaleFloats scale FLOATs from in buffer to out buffer
- * (ok for "in place" scale )
- *****************************************************************/
- void
- ScaleFloats(float *in, float *out, int length, float scaleFactor)
- /* in ptr to input
- out ptr to output
- length length of data
- scaleFactor input file to be scaled w/this factor */
- {
- int i;
-
- for (i = 0; i < length; i++)
- out[i] = in[i]*scaleFactor;
- } /* ------------------ end ScaleFloats() --------------- */
-
- /****************************************************************
- * SumFloats sum 2 buffers
- *****************************************************************/
- void
- SumFloats(float *in1, float *in2, float *out, int length)
- /* in1, in2 ptrs to input buffers
- out ptr to output buffer
- length length of buffers
- */
- {
- register int i;
-
- for (i = 0; i < length; i++)
- out[i] = in1[i] + in2[i];
- } /* ------------------ end SumFloats() --------------- */
-
- /****************************************************************
- * CopyFloats copy FLOATs from in buffer to out buffer
- *****************************************************************/
- void
- CopyFloats(float *in, float *out, int length)
- /* in ptr to input data
- out ptr to output data
- length length of data */
- {
- int i;
-
- for (i = 0; i < length; i++)
- out[i] = in[i];
- } /* ------------------ end CopyFloats() --------------- */
-
- /* **********************************************************************
- * DelayFloats: delay signal by N samples
- * ********************************************************************** */
- void
- DelayFloats(float *in, float *out, long length,
- float *delayBuffer, int delayLength, int *delayBufferPtr,
- char useCircularBuffer)
- /* in ptr to input buffer
- out ptr to output buffer
- length length of input buffer
- delayBuffer ptr to delay buffer
- delayLength length of delay buffer
- delayBufferPtr index of next read/write position in delay buffer.
- Need this if delayLength > length
- useCircularBuffer if TRUE, use circular buffer to preserve time in
- sample buffer. (Usually don't need this.)
- */
- {
- long i;
- long delayIndex, delayEndIndex;
- int firstHalfLength, secondHalfLength;
-
- /* do delay process w/circular buffer to preserve time in delay buffer */
- if ((delayLength > length)||(useCircularBuffer == TRUE))
- {
- delayEndIndex = delayLength-1;
-
- /* delay line ptr not near delay line end */
- if (*delayBufferPtr < delayEndIndex-length)
- {
- /* write delay buffer into output buffer */
- CopyFloats(&delayBuffer[*delayBufferPtr], out, length);
-
- /* write input into delay buffer into output buffer */
- CopyFloats(in, &delayBuffer[*delayBufferPtr], length);
-
- /* advance delay index (bounding check not needed) */
- *delayBufferPtr += length;
- }
-
- /* delay line ptr near delay line end */
- else
- {
- /* write delay buffer into output buffer */
- firstHalfLength = delayEndIndex - *delayBufferPtr;
- secondHalfLength = length-firstHalfLength;
- CopyFloats(&delayBuffer[*delayBufferPtr], out, firstHalfLength);
- CopyFloats(delayBuffer, &out[firstHalfLength], secondHalfLength);
-
- /* write input into delay buffer */
- CopyFloats(in, &delayBuffer[*delayBufferPtr], firstHalfLength);
- CopyFloats(&in[firstHalfLength], delayBuffer, secondHalfLength);
-
- /* advance and bound delay index */
- *delayBufferPtr += length;
- if (*delayBufferPtr > delayEndIndex)
- *delayBufferPtr -= delayEndIndex;
- }
- }
-
- /* do delay process w/gross copies. No need to adjust delay buffer ptr. This
- type of delay process doesn't preserve time of samples in delay buffer */
- else
- {
- /* write delay buffer into output buffer; write input into output buffer */
- CopyFloats(delayBuffer, out, delayLength);
- CopyFloats(in, &out[delayLength], length-delayLength);
-
- /* write input tail into delay buffer */
- CopyFloats(&in[length-delayLength], delayBuffer, delayLength);
- }
- } /* ----------------------- end DelayFloats() --------------------- */
-
- /****************************************************************
- * InterleaveNFloatsToShorts interleave N buffers
- *
- * Option to saturate to 16-bits.
- *
- * Input buffers are assumed to be of equal length
- * and data type.
- * Output buffer is N*length of input buffer. First
- * word of input buffer[0] will be first word of
- * output buffer
- *****************************************************************/
- void
- InterleaveNFloatsToShorts(float *inputs[], short *output, int inputLength,
- int interleaveFactor, char saturate)
- /* inputs ptr to array of input buffers
- output ptr to output buffer
- inputLength length of input buffer
- interleaveFactor # input buffers
- saturate if TRUE, do saturation
- */
- {
- register int i, j;
- register short *out;
- register float fValue;
- register float fCeiling, fFloor;
- register short iCeiling, iFloor;
-
- /* rounding = truncation + 1/2 bit DC offset -->> just truncate */
- /* convert buffer, no saturation */
- out = output;
- if (saturate == FALSE)
- {
- for (i = 0; i < inputLength; i++)
- {
- for (j = 0; j < interleaveFactor; j++)
- out[j] = (short) inputs[j][i];
- out += interleaveFactor;
- }
- }
- /* convert buffer w/saturation to integer range [iFloor..iCeiling] */
- else
- {
- fCeiling = 32767;
- fFloor = -32768;
- iCeiling = 32767; /* 2^15 - 1 */
- iFloor = -32768; /* -2^15 */
-
- for (i = 0; i < inputLength; i++)
- {
- for (j = 0; j < interleaveFactor; j++)
- {
- fValue = inputs[j][i];
- if (fValue > fCeiling)
- out[j] = iCeiling;
- else if (fValue < fFloor)
- out[j] = iFloor;
- else
- out[j] = (short) fValue;
- }
- out += interleaveFactor;
- }
- }
- } /* ------------------ end InterleaveNFloatsToShorts() --------------- */
-
- /* **********************************************************************
- * SecondsToSamples return time in units of samples
- * ********************************************************************** */
- int
- SecondsToSamples(double time, double samplingRate)
- /* time time (in seconds)
- samplingRate sampling rate (in samples per second)
- */
- {
- /* compute time in samples
- * Seconds * (samples/Second) = samples
- */
- if ((time >= 0)&&(samplingRate > 0))
- {
- return (int) (time*samplingRate);
- }
- /* report bogus parameters */
- if (time < 0)
- fprintf(stderr, "SecondsToSamples() bogus time (in seconds) %g\n", time);
- if (samplingRate <= 0)
- fprintf(stderr, "SecondsToSamples() bogus sampling rate %g\n", samplingRate);
-
- return (-1);
- } /* ------------------ end SecondsToSamples() --------------- */
-
- /*
- * LowerPrime given integer 'number', return prime <= 'number'.
- * If 'number' is prime, next prime lesser in value
- * will be returned. If no lesser prime exists,
- * return value will be 2, the least valued prime or
- *
- * ---------------------------------------------------------------------- */
- int
- LowerPrime(int number, int lowerBound)
- /* number number (> 1) to be checked for prime.
- lowerBound lowest number (> 1) to check for. (Need not be prime)
- */
- {
- /* check if input is < 2 */
- if (number < 2)
- return (2);
-
- /* check if lowerBound is < 2 */
- if (lowerBound < 2)
- lowerBound = 2;
-
- /* check that input is greater than lowerBound */
- if (number < lowerBound)
- return (lowerBound);
-
- /* spin around, looking for lesser prime */
- while ((IsPrime(number) == FALSE)&&(number >= lowerBound))
- number--;
-
- /* decide whether search reached lowerBound */
- if (number == lowerBound)
- return (lowerBound);
-
- return (number);
- } /* ----------------------- end LowerPrime() --------------------- */
-
- /*
- * UpperPrime given integer 'number', return prime >= 'number'
- * ---------------------------------------------------------------------- */
- int
- UpperPrime(int number, int upperBound)
- /* number number (> 1) to be checked for prime.
- upperBound highest number (> 1) to check for. (Need not be prime.) */
- {
- /* correct input < 2 */
- if (number < 2)
- number = 2;
-
- /* check if lowerBound is < 2 */
- if (upperBound < 2)
- return (2);
-
- /* check that input is less than upperBound */
- if (number > upperBound)
- return (upperBound);
-
- /* spin around, looking for greater prime */
- while ((IsPrime(number) == FALSE)&&(number <= upperBound))
- number++;
-
- /* decide whether search reached upperBound */
- if (number == upperBound)
- return (upperBound);
- else
- return (number);
- } /* ----------------------- end UpperPrime() --------------------- */
-
- /*
- * NearestPrime given integer 'number', return nearest prime.
- * if surrounding primes are equidistant, return greater
- * prime. If numer is prime, it is returned.
- * ---------------------------------------------------------------------- */
- int
- NearestPrime(int number, int lowerBound, int upperBound)
- /* number number (> 1) to be checked for prime.
- lowerBound lowest number (> 1) to check for. (Need not be prime)
- upperBound highest number (> 1) to check for. (Need not be prime)
- */
- {
- int lowerPrime, upperPrime;
-
- /* check to see if input is prime */
- if (IsPrime(number) == TRUE)
- return (number);
-
- /* find next prime greater in value */
- upperPrime = UpperPrime(number, upperBound);
-
- /* find next prime lesser in value */
- lowerPrime = LowerPrime(number, lowerBound);
-
- /*fprintf(stderr, "NearestPrime() loDiff=%d hiDiff=%d\n",
- number - lowerPrime, upperPrime - number);*/
-
- /* determine nearest prime */
- if ((upperPrime - number) <= (number - lowerPrime))
- return (upperPrime);
-
- return (lowerPrime);
- } /* ----------------------- end NearestPrime() --------------------- */
-
- /*
- * IsPrime given integer 'number', detemine if prime or not and
- * return flag (FALSE, TRUE)
- * ---------------------------------------------------------------------- */
- int
- IsPrime(int number)
- /* number value to test for primeness */
- {
- int i;
- int isPrime;
- int truncatedSquareRoot;
-
- /* if number is even, not prime */
- /* all numbers less than 2 can not be prime */
- if ((((number&0x1) == 0)&&(number != 2))||(number < 2))
- return(FALSE);
-
- /* A Composite Number a Will Always Posses A Prime Divisor p Satisfying
- * p <= sqrt(a)
-
- * Fundamental Theorem of Arithmetic
- (from Elementary Number Theory, 2nd Ed. by David M. Burton, p.48)
- Every positive integer n > 1 can be expressed as a product of primes;
- this representation is unique, apart from the order in which the factors
- occur
-
- * from Elementary Number Theory, 2nd Ed. by David M. Burton, p.52
-
- * "There is a property of composite numbers which allows us to reduce
- * materially the necessary computations - but still the above process
- * remains cumbersome. If an integer a > 1 is composite, then it may be
- * written as a = bc, where 1 < b < a and 1 < c < a. Assuming that b <= c,
- * we get b^2 <= bc = a and so b <= sqrt(a). Since b > 1, Fundamental Theorem
- * of Arithmetic ensures that b has at least one prime factor p. Then p <= b
- * <= sqrt(a); furthermore, because p|b and b|a, it follows that p|a. The
- * point is simply this a composite number a will always possess a prime
- * divisor p satisfying p <= sqrt(a)."
- */
- truncatedSquareRoot = (int) sqrt((double) number);
-
- /* this can definitely be sped up, w/look up table of primes */
- /* if number is not evenly divisible by any number <= truncatedSquareRoot,
- number is prime */
- for (i = 2; i <= truncatedSquareRoot; i++)
- {
- /* if modulus result is zero, number has been cleanly divided */
- if (number%i == 0)
- break;
- }
- /* figure out what broke loop. If result from modulus operation
- * is zero, then number is divisible by smaller number.
- * Thus, number is not prime
- */
- if (i > truncatedSquareRoot)
- return(TRUE);
-
- return(FALSE);
- } /* ----------------------- end IsPrime() --------------------- */
-